from math import cos, log, sin
from numbers import Number

__all__ = [
    "Dual",
]


class Dual:
    """对偶数"""

    __slots__ = 'x', 'y'

    def __init__(self, x: Number = 0, y: Number = 1):
        self.x, self.y = x, y

    def __neg__(self):
        return Dual(-self.x, -self.y)

    def __add__(self, other):
        if isinstance(other, Number):
            return Dual(self.x + other, self.y)
        elif isinstance(other, Dual):
            return Dual(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        if isinstance(other, Number):
            return Dual(self.x - other, self.y)
        elif isinstance(other, Dual):
            return Dual(self.x - other.x, self.y - other.y)

    def __mul__(self, other):
        if isinstance(other, Number):
            return Dual(self.x * other, self.y * other)
        elif isinstance(other, Dual):
            return Dual(self.x * other.x, self.x * other.y + self.y * other.x)

    def __truediv__(self, other):
        if isinstance(other, Number):
            return Dual(self.x / other, self.y / other)
        elif isinstance(other, Dual):
            return Dual(
                self.x * other.x / other.x ** 2,
                (-self.x * other.y + self.y * other.x) / other.x ** 2,
            )

    def __pow__(self, other):
        if isinstance(other, Number):
            return Dual(self.x ** other, self.y * other * self.x ** (other - 1))
        else:
            return NotImplemented

    def ln(self):
        return Dual(log(self.x), self.y / self.x)

    def conjugate(self):
        return Dual(self.x, -self.y)

    def __str__(self):
        return f"{self.x}{self.y:+}ε"

    def __repr__(self):
        return f"Dual({self.x}, {self.y})"

    def __complex__(self):
        return complex(self.x, self.y)

    def __int__(self):
        return int(self.x)

    def __float__(self):
        return float(self.x)

    def __bool__(self):
        return bool(self.x) and bool(self.y)

